import dataclasses
from typing import Any

from zkl_pyutils_serialization.basics import get_context_tag_value
from zkl_pyutils_serialization.convert import convert, registry
from zkl_pyutils_serialization.convertors.common import PyObjectFormat
from zkl_pyutils_serialization.tags import DstFormat, DstTypehint, SrcFormat, SrcType
from .format import JsonValueFormat
from .typing import JsonObject


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat})
def dataclass_serializer(value: Any) -> JsonObject:
    if not dataclasses.is_dataclass(get_context_tag_value(SrcType)):
        raise NotImplementedError
    if not dataclasses.is_dataclass(value):
        raise NotImplementedError

    converted_dict = {}
    for field in dataclasses.fields(value):
        field_name = field.name
        field_value = getattr(value, field_name)
        converted_key = convert(field_name, dst_typehint=str)
        converted_val = convert(field_value, src_typehint=field.type)
        converted_dict[converted_key] = converted_val
    return converted_dict


@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat})
def dataclass_deserializer(value: JsonObject) -> Any:
    typehint = get_context_tag_value(DstTypehint, Any)
    if not dataclasses.is_dataclass(typehint):
        raise NotImplementedError
    if not isinstance(value, dict):
        raise NotImplementedError

    fields_type_hint = {field.name: field.type for field in dataclasses.fields(typehint)}

    return typehint(**{
        convert(key, dst_typehint=str): convert(val, dst_typehint=fields_type_hint[key])
        for key, val in value.items()})
